package flexUnitTests 
{		
	import flash.utils.describeType;
	
	import flashx.textLayout.tlf_internal;
	
	import flex.persistence.EntityManager;
	import flex.persistence.EntityManagerFactory;
	import flex.persistence.Query;
	import flex.persistence.criteria.CriteriaBuilder;
	import flex.persistence.criteria.CriteriaQuery;
	import flex.persistence.criteria.Order;
	import flex.persistence.criteria.Predicate;
	import flex.persistence.criteria.Root;
	import flex.persistence.criteria.Selection;
	import flex.persistence.criteria.Subquery;
	
	import flexUnitTests.entities.EntityWithOneToMany;
	import flexUnitTests.entities.SimpleEntityAuto;
	import flexUnitTests.entities.SimpleEntityManual;
	
	import mx.effects.easing.Quadratic;
	import mx.graphics.shaderClasses.ExclusionShader;
	
	import org.airlink.persistence.AirLink;
	import org.flexunit.assertThat;
	import org.flexunit.asserts.assertEquals;
	import org.flexunit.asserts.assertNotNull;
	import org.flexunit.asserts.assertTrue;
	import org.flexunit.internals.namespaces.classInternal;
	import org.hamcrest.date.dateEqual;
	import org.hamcrest.number.greaterThan;
	
	[TestCase(order=11)]
	public class EntityManagerCriteriaTest {		
		public static var em:EntityManager; 
		
		
		private static var d:Date = new Date();
		
		public function EntityManagerCriteriaTest() {
			
		}
		

		[Before]
		public function setUp():void {
			
		
		}
		
		[After]
		public function tearDown():void {
		
		}
		
		[BeforeClass]
		public static function setUpBeforeClass():void {
			AirLink.initEntityManagers();
			em = EntityManagerFactory.createEntityManager();			
			
			var o1:SimpleEntityAuto = EntityFactory.createSimpleEntity(SimpleEntityAuto);
			o1.numberField = 1000;
			em.persist(o1);
			
			var field:String="oneToManyPersists";
			var nbSimpleEntityAuto:int = 3;			
			var oto:EntityWithOneToMany = new EntityWithOneToMany();
			oto[field] = new Array();
			var o:SimpleEntityAuto;
			for(var i:int = 0; i<nbSimpleEntityAuto; i++) {
				o = EntityFactory.createSimpleEntity(SimpleEntityAuto);
				o.numberField = 1000;
				oto[field].push(o);
				em.persist(o);
			} 
			em.persist(oto);			
			
			var o3:SimpleEntityAuto = EntityFactory.createSimpleEntity(SimpleEntityAuto);
			o3.integerField=5;
			o3.numberField = 1000;
			em.persist(o3);	

			var o4:SimpleEntityAuto = EntityFactory.createSimpleEntity(SimpleEntityAuto);
			o4.stringField = "5";
			o4.numberField = 1000;
			o4.dateField = d;
			em.persist(o4);	
			
			var o5:SimpleEntityAuto = EntityFactory.createSimpleEntity(SimpleEntityAuto);
			o5.numberField = 1000;
			o5.stringField=null;
			em.persist(o5);	
			
		}
		
		[AfterClass]
		public static function tearDownAfterClass():void {
		 
			
		}

		[Test(order=1)]
		public function testSimpleTypedQuery():void {
			var cb:CriteriaBuilder = em.getCriteriaBuilder();
			var query:CriteriaQuery = cb.createQuery(SimpleEntityAuto);		
			query.from(SimpleEntityAuto);		
			var tq:Query = em.createTypedQuery(query);			
			var res:Array = tq.getResultList() as Array;
			assertNotNull(res);						
		}
				
		[Test(order=2)]
		public function testEquals():void {
			var cb:CriteriaBuilder=em.getCriteriaBuilder();
			var query:CriteriaQuery=cb.createQuery(SimpleEntityAuto);
			var root:Root = query.from(SimpleEntityAuto);
			var condition:Predicate = cb.equal(root.get("integerField"), 500);
			var condition1:Predicate = cb.equal(root.get("numberField"), 1000);
			var condition2:Predicate = cb.and(condition, condition1);
			query.where(condition2);
			var tq:Query = em.createTypedQuery(query);
			var res:Array = tq.getResultList() as Array;
			assertNotNull(res);
		}

		[Test(order=3)]
		public function testGreaterThan():void{
			var cb:CriteriaBuilder=em.getCriteriaBuilder();
			var query:CriteriaQuery = cb.createQuery(SimpleEntityAuto);
			var root:Root = query.from(SimpleEntityAuto);
			var condition:Predicate = cb.greaterThan(root.get("integerField"),22);
			var condition1:Predicate = cb.equal(root.get("numberField"), 1000);
			var condition2:Predicate = cb.and(condition, condition1);
			query.where(condition2);
			var tq:Query = em.createTypedQuery(query);				
			var res:Array = tq.getResultList() as Array;
			assertNotNull(res);
		}

		[Test(order=4)]
		public function testGreaterThanOrEquals():void {
			var cb:CriteriaBuilder=em.getCriteriaBuilder();
			var query:CriteriaQuery=cb.createQuery(SimpleEntityAuto);
			var root:Root = query.from(SimpleEntityAuto);
			var condition:Predicate = cb.greaterThanOrEqualTo(root.get("integerField"), 22);		
			var condition1:Predicate = cb.equal(root.get("numberField"), 1000);
			var condition2:Predicate = cb.and(condition, condition1);
			query.where(condition2);
			var tq:Query = em.createTypedQuery(query);	
			var res:Array = tq.getResultList() as Array;
			assertNotNull(res);
		}
				
		[Test(order=5)]
		public function testBetween():void {
			var cb:CriteriaBuilder = em.getCriteriaBuilder();
			var query:CriteriaQuery=cb.createQuery(SimpleEntityAuto);
			var root:Root = query.from(SimpleEntityAuto);
			var condition:Predicate = cb.between(root.get("integerField"), 1, 600);
			var condition1:Predicate = cb.equal(root.get("numberField"), 1000);
			var condition2:Predicate = cb.and(condition, condition1);
			query.where(condition2);
			var tq:Query = em.createTypedQuery(query);			
			var res:Array = tq.getResultList() as Array;
			assertNotNull(res);			
		}
						
		[Test(order=6)]
		public function testLessThan():void {
			var cb:CriteriaBuilder = em.getCriteriaBuilder();
			var query:CriteriaQuery=cb.createQuery(SimpleEntityAuto);
			var root:Root = query.from(SimpleEntityAuto);
			var condition:Predicate = cb.lessThan(root.get("integerField"), 600);
			var condition1:Predicate = cb.equal(root.get("numberField"), 1000);
			var condition2:Predicate = cb.and(condition, condition1);
			query.where(condition2);
			var tq:Query = em.createTypedQuery(query);
			var res:Array = tq.getResultList() as Array;
			assertNotNull(res);
		}

		[Test(order=7)]
		public function testLessThanOrEqual():void {
			var cb:CriteriaBuilder = em.getCriteriaBuilder();
			var query:CriteriaQuery=cb.createQuery(SimpleEntityAuto);
			var root:Root = query.from(SimpleEntityAuto);
			var condition:Predicate = cb.lessThanOrEqualTo(root.get("integerField"), 600);
			var condition1:Predicate = cb.equal(root.get("numberField"), 1000);
			var condition2:Predicate = cb.and(condition, condition1);
			query.where(condition2);
			var tq:Query = em.createTypedQuery(query);
			var res:Array = tq.getResultList() as Array;
			assertNotNull(res);
		}
		
		[Test(order=8)]
		public function testOr():void {
			var cb:CriteriaBuilder = em.getCriteriaBuilder();
			var query:CriteriaQuery=cb.createQuery(SimpleEntityAuto);
			query.distinct(true);
			var root:Root = query.from(SimpleEntityAuto);
			var condition:Predicate = cb.lessThanOrEqualTo(root.get("integerField"),600);
			var condition2:Predicate = cb.gt(root.get("integerField"),5);
			var conditionOr:Predicate = cb.or(condition,condition2);			
			query.where(conditionOr);
			var tq:Query = em.createTypedQuery(query);
			var res:Array = tq.getResultList() as Array;
			assertNotNull(res);	
		}
		
		[Test(order=9)]
		public function testAnd():void {
			var cb:CriteriaBuilder = em.getCriteriaBuilder();
			var query:CriteriaQuery=cb.createQuery(SimpleEntityAuto);
			var root:Root = query.from(SimpleEntityAuto);
			var condition:Predicate = cb.lessThanOrEqualTo(root.get("integerField"),600);
			var condition2:Predicate = cb.gt(root.get("integerField"),5);
			var conditionAnd:Predicate = cb.and(condition,condition2);			
			query.where(conditionAnd);
			var tq:Query = em.createTypedQuery(query);
			var res:Array = tq.getResultList() as Array;
			assertNotNull(res);	
		}
		
		[Test(order=10)]
		public function testOrderByAsc():void {
			var cb:CriteriaBuilder = em.getCriteriaBuilder();
			var query:CriteriaQuery=cb.createQuery(SimpleEntityAuto);
			var root:Root = query.from(SimpleEntityAuto);
			var condition:Predicate = cb.lessThanOrEqualTo(root.get("integerField"),600);			
			query.where(condition);			
			var order:Order= cb.asc(root.get("integerField"));		
			query.orderBy(order);
			var tq:Query = em.createTypedQuery(query);
			var res:Array = tq.getResultList() as Array;
			assertNotNull(res);			
		}		
		
		[Test(order=11)]
		public function testOrderByDesc():void {
			var cb:CriteriaBuilder = em.getCriteriaBuilder();
			var query:CriteriaQuery=cb.createQuery(SimpleEntityAuto);
			var root:Root = query.from(SimpleEntityAuto);
			var condition:Predicate = cb.lessThanOrEqualTo(root.get("integerField"),600);			
			query.where(condition);
			var order:Order= cb.desc(root.get("integerField"));		
			query.orderBy(order);
			var tq:Query = em.createTypedQuery(query);
			var res:Array = tq.getResultList() as Array;
			assertNotNull(res);		
		}
		
		[Test(order=12)]
		public function testAvg():void {
			var cb:CriteriaBuilder = em.getCriteriaBuilder();
			var query:CriteriaQuery=cb.createQuery(Number);
			var root:Root = query.from(SimpleEntityAuto);
			var select:Selection = cb.avg(root.get("integerField"));  
			query.select(select);
			var condition:Predicate = cb.equal(root.get("numberField"), 1000);
			query.where(condition);
			var tq:Query = em.createTypedQuery(query);			
			var nb:Number = tq.getSingleResult() as Number;
//			trace(nb);
			assertEquals(nb, 429.2857142857143);
		}
		
		[Test(order=13)]
		public function testAbs():void {
			var cb:CriteriaBuilder = em.getCriteriaBuilder();
			var query:CriteriaQuery=cb.createQuery(int);
			var root:Root = query.from(SimpleEntityAuto);
			var select:Selection = cb.abs(root.get("integerField"));
			query.select(select);
			query.where(cb.equal(root.get("integerField"), new int(5)));
			var tq:Query = em.createTypedQuery(query);
			var nb:int = tq.getSingleResult() as int;			
			assertEquals(5, nb);			
		}
		
		[Test(order=14)]
		public function testCount():void {
			var cb:CriteriaBuilder = em.getCriteriaBuilder();
			var query:CriteriaQuery=cb.createQuery(int);
			var root:Root = query.from(SimpleEntityAuto);
			var select:Selection = cb.count(root.get("integerField"));
			query.select(select);
			var tq:Query = em.createTypedQuery(query);
			var nb:int = tq.getSingleResult() as int;			
			assertTrue(nb>=7);
		}
		
		[Test(order=15)]
		public function testMax():void {
			var cb:CriteriaBuilder = em.getCriteriaBuilder();
			var query:CriteriaQuery=cb.createQuery(int);
			var root:Root = query.from(SimpleEntityAuto);
			var select:Selection = cb.max(root.get("integerField"));
			query.select(select);
			var tq:Query = em.createTypedQuery(query);
			var nb:int = tq.getSingleResult() as int;			
			assertTrue(nb>=500);
		}
		
		[Test(order=16)]
		public function testMin():void {
			var cb:CriteriaBuilder = em.getCriteriaBuilder();
			var query:CriteriaQuery=cb.createQuery(int);
			var root:Root = query.from(SimpleEntityAuto);
			var select:Selection = cb.min(root.get("integerField"));
			query.select(select);
			var tq:Query = em.createTypedQuery(query);
			var nb:int = tq.getSingleResult() as int;			
			assertTrue(nb<=5);
		}
		
		[Test(order=17)]
		public function testIsNull():void {
			var cb:CriteriaBuilder = em.getCriteriaBuilder();
			var query:CriteriaQuery=cb.createQuery(SimpleEntityAuto);
			var root:Root = query.from(SimpleEntityAuto);
			query.where(cb.isNull(root.get("integerField")));
			var order:Order= cb.desc(root.get("stringField"));		
			query.orderBy(order);
			var tq:Query = em.createTypedQuery(query);
			var res:Array = tq.getResultList() as Array;
			assertNotNull(res);	
		}
		
		[Test(order=18)]
		public function testIsNotNull():void {
			var cb:CriteriaBuilder = em.getCriteriaBuilder();
			var query:CriteriaQuery=cb.createQuery(SimpleEntityAuto);
			var root:Root = query.from(SimpleEntityAuto);
			query.where(cb.isNotNull(root.get("integerField")));
			var order:Order= cb.desc(root.get("stringField"));		
			query.orderBy(order);
			var tq:Query = em.createTypedQuery(query);
			var res:Array = tq.getResultList() as Array;
			assertNotNull(res);	
		}
		
		[Test(order=19)]
		public function testSimpleTypedQueryWithOneToMany():void {
				
			var cb:CriteriaBuilder = em.getCriteriaBuilder();
			var query:CriteriaQuery = cb.createQuery(EntityWithOneToMany);		
			query.from(EntityWithOneToMany);		
			var tq:Query = em.createTypedQuery(query);			
			var res:Array = tq.getResultList() as Array;
			assertNotNull(res);	
			var test:EntityWithOneToMany = res.pop();
			assertNotNull(test.oneToManyPersists);
			assertEquals(test.oneToManyPersists.pop().integerField,500);			
		}
		
		[Test(order=20)]
		public function testMultipleTables():void {					
			var cb:CriteriaBuilder = em.getCriteriaBuilder();
			var query:CriteriaQuery = cb.createQuery(SimpleEntityAuto);		
			var root:Root=query.from(SimpleEntityAuto);
			var root2:Root=query.from(SimpleEntityAuto);
			query.where(cb.equal(root.get("integerField"),root2.get("stringField")));			
			var tq:Query = em.createTypedQuery(query);			
			var res:Array = tq.getResultList() as Array;
			assertNotNull(res);			
		}
		
		[Test(order=21)] 
		public function testGroupBy():void {
			var cb:CriteriaBuilder = em.getCriteriaBuilder();
			var query:CriteriaQuery=cb.createQuery(uint);
			var root:Root = query.from(SimpleEntityAuto);			
			query.select(cb.max(root.get("integerField")));
			query.groupBy(root.get("integerField")).having(cb.greaterThanOrEqualTo(root.get("integerField"),10));
			var tq:Query = em.createTypedQuery(query);
			var nb:Array = tq.getResultList();			
			assertNotNull(nb);			
		}
		[Test(order=22)]
		public function testSubQuery():void {
			var cb:CriteriaBuilder=em.getCriteriaBuilder();
		
			var query:CriteriaQuery=cb.createQuery(uint);
			var root:Root = query.from(SimpleEntityAuto);		
			query.select(cb.max(root.get("integerField")));
			
			var sub:Subquery=query.subquery(uint);			
			var root2:Root=sub.from(SimpleEntityAuto);
			sub.select(root2.get("integerField"));
			sub.where(cb.equal(root2.get("stringField"),"5"));
			
			var condition:Predicate = cb.equal(root.get("integerField"),sub);			
			query.where(condition);
			var tq:Query = em.createTypedQuery(query);
			var nb:Array = tq.getResultList();		
						
			assertNotNull(nb);			
		}
		
		[Test(order=23)]
		public function testWithDate():void {
			// 
			var cb:CriteriaBuilder = em.getCriteriaBuilder();
			var query:CriteriaQuery=cb.createQuery(Date);
			var root:Root = query.from(SimpleEntityAuto);			
			query.select(root.get("dateField"));
			var condition:Predicate = cb.equal(root.get("stringField"), "5");
			var condition1:Predicate = cb.equal(root.get("numberField"), 1000);
			var condition2:Predicate = cb.and(condition, condition1);
			query.where(condition2);
			var tq:Query = em.createTypedQuery(query);
			var date1:Date = tq.getSingleResult() as Date;
			trace(date1+ "== "+d);
			assertThat(date1, dateEqual(d));
		}

		[Test(order=24)]
		public function testLessThanDate():void {
			// select * from SIMPLEENTITYAUTO t0 where((((t0.DATEFIELD<:p0))and((t0.NUMBERFIELD = :p1))))
			trace("testGreaterThanDate");
			var cb:CriteriaBuilder=em.getCriteriaBuilder();
			var query:CriteriaQuery=cb.createQuery(SimpleEntityAuto);
			var root:Root = query.from(SimpleEntityAuto);
			var condition:Predicate = cb.lessThan(root.get("dateField"), d);		
			var condition1:Predicate = cb.equal(root.get("numberField"), 1000);
			var condition2:Predicate = cb.and(condition, condition1);
			query.where(condition2);
			var tq:Query = em.createTypedQuery(query);	
			var res:Array = tq.getResultList() as Array;
			
			assertEquals(res.length, 6);
		}
		
	/*	[Test(order=25)]
		public function testExists():void {
			var cb:CriteriaBuilder = em.getCriteriaBuilder();
			var query:CriteriaQuery=cb.createQuery(SimpleEntityAuto);
			var root:Root = query.from(SimpleEntityAuto);
		
			var sub:Subquery=query.subquery(uint);			
			var root2:Root=sub.from(SimpleEntityAuto);			
			sub.where(cb.equal(root2.get("stringField"),root.get("stringField")));
			query.where(cb.exists(sub));	
			var tq:Query = em.createTypedQuery(query);
			var res:Array = tq.getResultList() as Array;
			assertNotNull(res);			
		}*/
		
	}
}